package fun.qu_an.minecraft.mini_games_helper.config;


import fun.qu_an.minecraft.mini_games_helper.MiniGamesHelper;
import lombok.Getter;
import me.shedaniel.autoconfig.AutoConfig;
import me.shedaniel.autoconfig.ConfigData;
import me.shedaniel.autoconfig.ConfigHolder;
import me.shedaniel.autoconfig.annotation.Config;
import me.shedaniel.autoconfig.annotation.ConfigEntry;
import me.shedaniel.autoconfig.serializer.GsonConfigSerializer;
import net.fabricmc.fabric.api.networking.v1.*;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.world.GameMode;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

@Getter
@Config(name = MiniGamesHelper.MOD_ID)
public class MiniGamesHelperConfig implements ConfigData {
	public static final String END_OF_OPTION = "mgh:end_of_option";

	static {
		AutoConfig.register(MiniGamesHelperConfig.class, GsonConfigSerializer::new);
	}

	private static final ConfigHolder<MiniGamesHelperConfig> configHolder = AutoConfig.getConfigHolder(MiniGamesHelperConfig.class);
	Group survival = new Group();
	Group creative = new Group();
	Group adventure = new Group();
	Group spectator = new Group();

	public static MiniGamesHelperConfig get() {
		return configHolder.get();
	}

	public static boolean load() {
		return configHolder.load();
	}

	public PacketByteBuf serialize() {
		PacketByteBuf buf = PacketByteBufs.create();
		serialize(buf);
		return buf;
	}

	public void serialize(PacketByteBuf buf) {
		serialize(buf, survival);
		serialize(buf, creative);
		serialize(buf, adventure);
		serialize(buf, spectator);
	}

	private void serialize(PacketByteBuf buf, Group group) {
		buf.writeBoolean(group.disableHitBox);
		buf.writeBoolean(group.hidePlayerListGameMode);
		buf.writeBoolean(group.disableRecipeBook);
		buf.writeBoolean(group.forceShader.enabled);
		buf.writeBoolean(group.forceShader.tryServerResourcePack);
		buf.writeString(group.forceShader.shaderPrompt);
		buf.writeString(group.forceShader.shaderHash);
		buf.writeString(group.forceShader.shaderUrl);
		buf.writeBoolean(group.forceColorSpace.enabled);
		buf.writeInt(group.forceColorSpace.colorSpace.ordinal());
		for (Option option : group.options) {
			buf.writeString(option.key);
			buf.writeString(option.value);
		}
		buf.writeString(END_OF_OPTION);
	}

	public MiniGamesHelperConfig deserialize(PacketByteBuf buf) {
		MiniGamesHelperConfig config = new MiniGamesHelperConfig();
		deserialize(config.survival, buf);
		deserialize(config.creative, buf);
		deserialize(config.adventure, buf);
		deserialize(config.spectator, buf);
		return config;
	}

	private void deserialize(Group group, PacketByteBuf buf) {
		group.disableHitBox = buf.readBoolean();
		group.hidePlayerListGameMode = buf.readBoolean();
		group.disableRecipeBook = buf.readBoolean();
		group.forceShader.enabled = buf.readBoolean();
		group.forceShader.tryServerResourcePack = buf.readBoolean();
		group.forceShader.shaderPrompt = buf.readString();
		group.forceShader.shaderHash = buf.readString();
		group.forceShader.shaderUrl = buf.readString();
		group.forceColorSpace.enabled = buf.readBoolean();
		group.forceColorSpace.colorSpace = MGHColorSpace.values()[buf.readInt()];
		group.options = readOptions(buf);
	}

	private Option[] readOptions(PacketByteBuf buf) {
		List<Option> l = new ArrayList<>();
		while (buf.readableBytes() > 0) {
			String key = buf.readString();
			if (key.equals(END_OF_OPTION)) {
				return l.toArray(Option[]::new);
			}
			Option o = new Option();
			o.key = key;
			o.value = buf.readString();
			l.add(o);
		}
		throw new IllegalStateException("buf has no end sign");
	}

	public Optional<MGHColorSpace> getColorSpace(GameMode gameMode) {
		return Optional.ofNullable(switch (gameMode) {
			case SURVIVAL -> survival.forceColorSpace.enabled ? survival.forceColorSpace.colorSpace : null;
			case CREATIVE -> creative.forceColorSpace.enabled ? creative.forceColorSpace.colorSpace : null;
			case ADVENTURE -> adventure.forceColorSpace.enabled ? adventure.forceColorSpace.colorSpace : null;
			case SPECTATOR -> spectator.forceColorSpace.enabled ? spectator.forceColorSpace.colorSpace : null;
		});
	}

	public boolean shouldTryServerRP(GameMode gameMode) {
		return switch (gameMode) {
			case SURVIVAL -> survival.forceShader.enabled && survival.forceShader.tryServerResourcePack;
			case CREATIVE -> creative.forceShader.enabled && creative.forceShader.tryServerResourcePack;
			case ADVENTURE -> adventure.forceShader.enabled && adventure.forceShader.tryServerResourcePack;
			case SPECTATOR -> spectator.forceShader.enabled && spectator.forceShader.tryServerResourcePack;
		};
	}

	public boolean isDisableHitBox(GameMode gameMode) {
		return switch (gameMode) {
			case SURVIVAL -> survival.disableHitBox;
			case CREATIVE -> creative.disableHitBox;
			case ADVENTURE -> adventure.disableHitBox;
			case SPECTATOR -> spectator.disableHitBox;
		};
	}

	public boolean isHidePlayerList(GameMode gameMode) {
		return switch (gameMode) {
			case SURVIVAL -> survival.hidePlayerListGameMode;
			case CREATIVE -> creative.hidePlayerListGameMode;
			case ADVENTURE -> adventure.hidePlayerListGameMode;
			case SPECTATOR -> spectator.hidePlayerListGameMode;
		};
	}

	public boolean isDisableRecipeBook(GameMode gameMode) {
		return switch (gameMode) {
			case SURVIVAL -> survival.disableRecipeBook;
			case CREATIVE -> creative.disableRecipeBook;
			case ADVENTURE -> adventure.disableRecipeBook;
			case SPECTATOR -> spectator.disableRecipeBook;
		};
	}

	public static class Group {
		boolean disableHitBox = false;
		boolean hidePlayerListGameMode = false;
		boolean disableRecipeBook = false;
		ForceShader forceShader = new ForceShader();
		ForceColorSpace forceColorSpace = new ForceColorSpace();
		@Getter
		Option[] options = new Option[0];
	}

	public static class ForceShader {
		boolean enabled = false;
		boolean tryServerResourcePack = true;
		@Getter
		String shaderPrompt = "";
		@Getter
		String shaderHash = "";
		@Getter
		String shaderUrl = "";
	}

	public static class ForceColorSpace {
		boolean enabled = false;
		@ConfigEntry.Gui.Excluded
		String __comment_colorSpace = "Available values: " + Arrays.toString(MGHColorSpace.values());
		MGHColorSpace colorSpace = MGHColorSpace.SRGB;
	}

	public static class Option {
		@Getter
		String key = "";
		@Getter
		String value = "";
	}

//	@ConfigEntry.Gui.CollapsibleObject
//	InnerStuff stuff = new InnerStuff();
//
//	@ConfigEntry.Gui.Excluded
//	InnerStuff invisibleStuff = new InnerStuff();

//	static class InnerStuff {
//		int a = 0;
//		int b = 1;
//	}

}
